/*
 * Copyright 2011 Angel Sanadinov
 *
 * This file is part of VBox WMI.
 *
 * VBox WMI is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * VBox WMI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with VBox WMI.  If not, see <http://www.gnu.org/licenses/>.
 */

package ApplicationManagement;

import Beans.Requests.RequestBean;
import Utilities.Constants;
import Managers.LogsManager;
import Managers.Utilities.User;
import Utilities.ParameterNames;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * This class represents a service request validation filter. <br><br>
 *
 * All requests to the services pass through this filter and the requestor IDs are
 * checked, to make sure that the client ID that is sent with the request is
 * the ID of the client that sent it. <br><br>
 *
 * This should always be true, unless there is an error in the application and/or
 * improper modifications have been made. <br><br>
 *
 * <b>Note:</b> <i>An exception is thrown if an ID mismatch has been found and
 * the event is logged in the system event log file.</i>
 *
 * @author Angel Sanadinov
 */
public class ServiceRequestVerification implements Filter
{
    private ServletContext context;  //filter context
    private LogsManager logsManager; //logs manager

    /**
     * Initializes the filter.
     *
     * @param filterConfig filter configuration
     *
     * @throws ServletException if an exception occurs that interrupts the filter's
     *                          normal operation
     *
     * @see Filter#init()
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
    {
        context = filterConfig.getServletContext();
    }

    /**
     * Ends the filter's life-cycle and cleans up any object references.
     *
     * @see Filter#destroy()
     */
    @Override
    public void destroy()
    {
        context = null;
        logsManager = null;
    }

    /**
     * Processes the request. <br><br>
     *
     * Checks if the request (if available) that is being sent to a service is
     * authentic (the client id that is being sent with the request is the same
     * as the id of the client that sent it).
     *
     * @param request a ServletRequest object that contains the request the
     *                client has made of the servlet
     * @param response a ServletResponse object that contains the response
     *                 the servlet sends to the client
     * @param chain the chain of filters to be executed for the request
     *
     * @throws IOException if an input or output error is detected when the filter
     *                     handles the request
     * @throws ServletException if the request could not be handled
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException
    {
        //retrieves the logs manager, if it is not available
        if(logsManager == null)
            logsManager = (LogsManager)context.getAttribute(Constants.CONTEXT_LOGS_MANAGER);
        else
            ;

        //checks if an HTTP request was made and if the logs manager was retrieved
        if(request instanceof HttpServletRequest && logsManager != null)
        {
            HttpServletRequest httpRequest = (HttpServletRequest)request;
            RequestBean serviceRequest = null;

            //retrieves the names of the attributes in the request
            Enumeration<String> atrributeNames = request.getAttributeNames();
            while(atrributeNames.hasMoreElements())
            {
                //retrieves an attribute
                Object currentAttribute = request.getAttribute(atrributeNames.nextElement());

                //checks if the current attribute is a request for a service
                if(currentAttribute instanceof RequestBean)
                {
                    //a service request was found...
                    serviceRequest = (RequestBean)currentAttribute;
                    break;
                }
                else
                    ;
            }

            //checks if a service request was found
            if(serviceRequest != null)
            {
                //retrieves the requestor data from the client session
                User userSessionData =
                        (User)httpRequest.getSession().getAttribute(ParameterNames.SESSION_USER_OBJECT);

                //checks if the session data is available and valid, and that the id in the session data
                //matches the id in the request (ie: this is not an attempt to use another user's credentials)
                if(userSessionData != null && userSessionData.isValid()
                   && userSessionData.getUserData().getUserId() == serviceRequest.getRequestorId())
                   chain.doFilter(request, response); //goes to the next filter or the requested resource
                else //invalid user data was found or there is a mismatch in the IDs
                {
                    //logs the event and throws an exception; the request must not reach the service
                    String errorMessage = "Client data is invalid or requestor and client session IDs do not match.";
                    logsManager.logSystemEvent(System.currentTimeMillis(), Constants.LOG_SEVERITY_WARNING, errorMessage);
                    throw new ServletException(errorMessage);
                }
            }
            else //there is no request, let the service deal with it
                chain.doFilter(request, response);
        }
        else //terminates the operation; w/o the proper data the validity of the request cannot be determined
            throw new ServletException("Failed to retrieve HTTP request object and/or logs manager");
    }
}
